package zoz.cool.jahub.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.wf.captcha.SpecCaptcha;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import zoz.cool.jahub.client.EmailClient;
import zoz.cool.jahub.client.RedisClient;
import zoz.cool.jahub.client.SmsClient;
import zoz.cool.jahub.constant.CommonConstant;
import zoz.cool.jahub.domain.JahubUser;
import zoz.cool.jahub.enums.ResultCode;
import zoz.cool.jahub.exception.ApiException;
import zoz.cool.jahub.service.JahubLoginLogService;
import zoz.cool.jahub.service.JahubUserService;
import zoz.cool.jahub.service.UserService;
import zoz.cool.jahub.utils.ToolKit;
import zoz.cool.jahub.vo.CaptchaVo;
import zoz.cool.jahub.vo.LoginVo;
import zoz.cool.jahub.vo.RegisterVo;
import zoz.cool.jahub.vo.VerifyCodeVo;

/**
 * 注册管理
 */
@Slf4j
@RestController
@ResponseBody
@RequestMapping("/api")
@Tag(name = "RegisterController", description = "注册管理")
public class RegisterController {
    @Resource
    private RedisClient redisClient;
    @Resource
    private EmailClient emailClient;
    @Resource
    private SmsClient smsClient;
    @Resource
    private JahubUserService jahubUserService;
    @Resource
    private UserService userService;

    @Operation(summary = "用户注册", description = "用户注册接口")
    @PostMapping("/register")
    @ResponseBody
    public JahubUser register(@Validated @RequestBody RegisterVo registerVo) {
        JahubUser jahubUser = new JahubUser();
        BeanUtils.copyProperties(registerVo, jahubUser);
        // 用户名是否已存在
        if (jahubUserService.getUser(jahubUser.getUsername()) != null) {
            throw new ApiException("该用户名已存在");
        }
        // 邮箱号或手机号是否已存在
        String email = jahubUser.getEmail();
        if (StrUtil.isNotEmpty(email) && jahubUserService.getUser(email) != null) {
            // 邮箱已存在
            throw new ApiException("该邮箱已注册");
        }
        String phone = jahubUser.getPhone();
        if (StrUtil.isNotEmpty(phone) && jahubUserService.getUser(phone) != null) {
            // 手机号已存在
            throw new ApiException("该手机号已注册");
        }
        if (StrUtil.isEmpty(email) && StrUtil.isEmpty(phone)) {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "邮箱和手机号不能同时为空");
        }
        if (!registerVo.getPassword().equals(registerVo.getPasswordAgain())) {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "两次密码不一致");
        }
        String emailOrPhone = StrUtil.isNotEmpty(email) ? email : phone;
        String REGISTER_VERIFY_CODE = CommonConstant.VERIFY_CODE_KEY_PREFIX + emailOrPhone;
        String storeCode = (String) redisClient.get(REGISTER_VERIFY_CODE);
        if (StrUtil.isEmpty(storeCode) || !storeCode.equals(registerVo.getVerifyCode())) {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "验证码不正确或已过期");
        }
        jahubUser.setPassword(ToolKit.getEncryptPassword(registerVo.getPassword()));
        jahubUserService.save(jahubUser);
        return jahubUser;
    }

    @Operation(summary = "图形验证码", description = "图形验证码接口")
    @GetMapping("/captcha")
    public CaptchaVo captcha() {
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
        String verCode = specCaptcha.text().toLowerCase();
        // 生成一个uuid作为key
        String key = ToolKit.getUUID();
        // 存入redis并设置过期时间
        redisClient.set(CommonConstant.VERIFY_CODE_KEY_PREFIX + key, verCode, CommonConstant.VERIFY_CODE_EXPIRE);
        // 将key和base64返回给前端
        return new CaptchaVo(key, specCaptcha.toBase64());
    }

    @Operation(summary = "验证码", description = "验证码接口")
    @PostMapping("/verify-code")
    public String verifyCodePhone(@Validated @RequestBody VerifyCodeVo verifyCodeVo) {
        if (verifyCodeVo.getPhone() == null && verifyCodeVo.getEmail() == null) {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "邮箱和手机号不能同时为空");
        }
        String capKey = CommonConstant.VERIFY_CODE_KEY_PREFIX + verifyCodeVo.getCaptchaKey();
        String capCode = (String) redisClient.get(capKey);
        if (StrUtil.isEmpty(capCode) || !capCode.equals(verifyCodeVo.getCaptchaCode().toLowerCase())) {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "图形验证码不正确或已过期");
        }
        String key = verifyCodeVo.getPhone() == null ? verifyCodeVo.getEmail() : verifyCodeVo.getPhone();
        // 生成一个6位数的随机验证码
        String verCode = ToolKit.getRandomCode();
        // 存入redis并设置过期时间
        String verifyCodeKey = CommonConstant.VERIFY_CODE_KEY_PREFIX + key;
        redisClient.set(verifyCodeKey, verCode, CommonConstant.VERIFY_CODE_EXPIRE);
        if (StrUtil.isNotEmpty(verifyCodeVo.getEmail())) {
            emailClient.sendMailVerifyCode(verifyCodeVo.getEmail(), verCode);
            return "邮件已发送到您的邮箱，请查收！";
        } else {
            smsClient.sendSmsVerifyCode(verifyCodeVo.getPhone(), verCode);
            return "短信已发送到您的手机，请查收！";
        }
    }

    @Operation(summary = "用户登录", description = "用户登录接口")
    @PostMapping("/login")
    @ResponseBody
    public String login(@Validated @RequestBody LoginVo loginVo) {
        JahubUser user;
        if (StrUtil.isNotEmpty(loginVo.getUsername())) {// 账号密码登录
            Assert.notNull(loginVo.getPassword(), "密码不能为空！");
            user = jahubUserService.getUser(loginVo.getUsername());
            if (user == null || !user.getPassword().equals(ToolKit.getEncryptPassword(loginVo.getPassword()))) {
                throw new ApiException(ResultCode.VALIDATE_FAILED, "用户名或密码错误");
            }
        } else if (StrUtil.isNotEmpty(loginVo.getEmail()) || StrUtil.isNotEmpty(loginVo.getPhone())) {// 邮箱/手机验证码登录
            Assert.notNull(loginVo.getVerifyCode(), "验证码不能为空！");
            String key = StrUtil.isNotEmpty(loginVo.getEmail()) ? loginVo.getEmail() : loginVo.getPhone();
            String verifyCode = (String) redisClient.get(CommonConstant.VERIFY_CODE_KEY_PREFIX + key);
            Assert.notNull(verifyCode, "验证码已过期！");
            if (!verifyCode.equals(loginVo.getVerifyCode())) {
                throw new ApiException(ResultCode.VALIDATE_FAILED, "验证码错误");
            }
            user = jahubUserService.getUser(key);
        } else {
            throw new ApiException(ResultCode.VALIDATE_FAILED, "用户名、邮箱、手机号不能同时为空");
        }
        Assert.notNull(user, "登录异常，用户信息不存在！");
        // 密码校验成功后登录，一行代码实现登录
        StpUtil.login(user.getId());
        // 获取当前登录用户Token信息
        SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();
        userService.insertLoginLog(user.getId());
        return saTokenInfo.toString();
    }
}
